package com.itheima.dubbo.mongodb.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.commons.pojo.mongo.UserLocation;
import com.itheima.commons.vo.reception.UserLocationVo;
import com.itheima.dubbo.interfaces.UserLocationApi;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.GetQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;

/**
 * @author yaohu
 * @date 2021/12/13
 * @Version 1.0
 * @describe
 */
@Service
public class UserLocationApiImpl implements UserLocationApi {

    @Autowired
    private ElasticsearchTemplate esTemplate;

    @PostConstruct
    public void initIndex() {
        // 如果索引不存在
        if (!esTemplate.indexExists(UserLocation.class)) {
            // 创建索引
            if (esTemplate.createIndex(UserLocation.class)) {
                // 添加映射
                esTemplate.putMapping(UserLocation.class);
            }
        }
    }

    /**
     * 上传/更新用户位置信息
     *
     * @param userId    用户id
     * @param longitude 经度
     * @param latitude  纬度
     * @param address   位置描述
     */
    @Override
    public Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
        // 先判断 当前用户是否已经存在
        GetQuery getQuery = new GetQuery();
        getQuery.setId(userId.toString());
        UserLocation userLocation = esTemplate.queryForObject(getQuery, UserLocation.class);
        if (ObjectUtil.isNull(userLocation)) {
            UserLocation location = new UserLocation();
            location.setUserId(userId);
            location.setLocation(new GeoPoint(latitude, longitude));
            location.setAddress(address);
            location.setCreated(System.currentTimeMillis());
            location.setUpdated(location.getCreated());
            location.setLastUpdated(location.getCreated());

            // 1.为空 新增
            String insertIndex = esTemplate.index(new IndexQueryBuilder().withObject(location).build());
            return insertIndex != null;
        }
        // 2.不为空 更新
        UpdateQuery updateQuery = new UpdateQuery();
        // 更新哪个索引
        updateQuery.setClazz(UserLocation.class);
        // 更新索引中的哪个记录
        updateQuery.setId(userId.toString());
        // 更新内容
        UpdateRequest updateRequest = new UpdateRequest();
        // 如果添加对象，会出现属性覆盖的问题，map则不会
        HashMap<String, Object> map = new HashMap<>();
        map.put("location", new GeoPoint(latitude, longitude));
        map.put("address", address);
        updateRequest.doc(map);
        updateQuery.setUpdateRequest(updateRequest);
        UpdateResponse update = esTemplate.update(updateQuery);
        return update.getResult().getOp() >= 1;
    }

    /**
     * 通过用户id搜索用户位置信息
     *
     * @param userId
     * @return
     */
    @Override
    public UserLocationVo queryByUserId(Long userId) {
        GetQuery getQuery = new GetQuery();
        getQuery.setId(userId.toString());
        UserLocation userLocation = esTemplate.queryForObject(getQuery, UserLocation.class);
        return UserLocationVo.format(userLocation);
    }

    /**
     * 根据位置搜索
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  距离(米)
     * @param counts    要搜索的条数
     * @return
     */
    @Override
    public List<UserLocationVo> queryUserFromLocation(Double longitude, Double latitude, Double distance, Integer counts) {
        List<UserLocation> userLocationList = esTemplate.queryForList(new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.geoDistanceQuery("location")
                        .point(latitude, longitude)
                        .distance(distance / 1000, DistanceUnit.KILOMETERS))
                .withSort(SortBuilders.geoDistanceSort("location", latitude, longitude).order(SortOrder.ASC))
                .withPageable(PageRequest.of(0, counts))
                .build(), UserLocation.class);
        return UserLocationVo.formatToList(userLocationList);
    }
}
